﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web;
using System.Xml;

using Xpus.Website.Configuration;

namespace Xpus.Website.Utilities
{
	/// <summary>
	/// 语言工具，用于根据当前请求的语言返回适当的资源。
	/// </summary>
	public static class LanguageUtility
	{
		// 存放语言文件中所有的字符串。
		// 其Key是语言的名字，如zh-CN等。
		// 其Value是一个Dictionary<string, string>，表示某种语言下的所有字符串。
		// 这个Value的Key表示字符串的资源名字，其Value就是具体的字符串。
		private static Dictionary<string, Dictionary<string, string>> _strings;

		/// <summary>
		/// 初始化所有语言的资源。
		/// </summary>
		static LanguageUtility()
		{
			LoadStrings();
		}

		/// <summary>
		/// 根据当前语言获取字符串资源。
		/// </summary>
		/// <param name="name">字符串的资源名字。</param>
		/// <returns>
		/// 与当前语言相关的字符串。
		/// 如果资源名字不存在，则返回资源名字本身。
		/// </returns>
		public static string GetString(string name)
		{
			string language = GetCurrentCulture().ToLower();
			if(_strings[language].ContainsKey(name))
				return _strings[language][name];
			else
				return name;
		}

		/// <summary>
		/// 根据当前语言获取邮件模板。
		/// </summary>
		/// <param name="name">邮件模板的资源名字。</param>
		/// <returns>与当前语言相关的邮件模板。</returns>
		public static string GetMailTemplate(string name)
		{
			return null;
		}

		/// <summary>
		/// 获取语言代码。如zh-CN的语言代码是zh。
		/// </summary>
		/// <param name="culture">语言的名字。</param>
		/// <returns>语言名字中的语言代码部分。</returns>
		private static string GetLanguageCode(string culture)
		{
			if(!culture.Contains("-"))
				return culture;

			int pos = culture.IndexOf("-");
			return culture.Substring(0, pos);
		}

		/// <summary>
		/// 获取某一个语言代码下面，系统支持的第一种文字。
		/// </summary>
		/// <param name="languageCode">语言代码，如 zh。</param>
		/// <returns>
		/// 对应于 <paramref name="languageCode"/>，
		/// 系统支持的第一种语言，如 zh-CN。
		/// 如果没有找到，返回null。
		/// </returns>
		private static string GetFirstSupportLanguage(string languageCode)
		{
			string langcode = languageCode.Contains("-") ?
				GetLanguageCode(languageCode) : languageCode;

			foreach(LanguageMappingConfiguration map in XpusConfigurationSection.Instance.Language.Mappings)
			{
				if(map.Code == langcode)
					return map.Language;
			}
			return null;
		}

		/// <summary>
		/// 获取系统支持的语言。
		/// </summary>
		/// <returns>
		/// 返回系统所支持的语言。如果都不支持，返回默认语言。
		/// </returns>
		private static string GetCurrentCulture()
		{
			string[] userLanguages = HttpContext.Current.Request.UserLanguages;

			if(userLanguages == null)
				return XpusConfigurationSection.Instance.Language.DefaultLanguage;

			// 尝试直接支持的语言。
			foreach(string lang in userLanguages)
			{
				string langstr = lang;

				// 浏览器中设置的非首选语言，形式是这样的：
				// en-US;q=0.8
				// q表示其优先级。但所需要的只是分号前面的部分。
				if(lang.Contains(";"))
				{
					int pos = lang.IndexOf(";");
					langstr = lang.Substring(0, pos);
				}

				if(IsSupportedLanguage(langstr))
					return langstr;

				langstr = GetFirstSupportLanguage(langstr);

				if(langstr != null && IsSupportedLanguage(langstr))
					return langstr;
			}

			return XpusConfigurationSection.Instance.Language.DefaultLanguage;
		}

		/// <summary>
		/// 获取系统是否支持一种语言。
		/// </summary>
		/// <param name="culture">语言的名字，类似于 zh-cn 这样的。</param>
		/// <returns>如果支持，返回 true；否则返回 false。</returns>
		private static bool IsSupportedLanguage(string culture)
		{
			return _strings.ContainsKey(culture.ToLower());
		}

		/// <summary>
		/// 从配置文件设定的语言文件目录中加载语言文件。
		/// </summary>
		private static void LoadStrings()
		{
			string path = HttpContext.Current.Server.MapPath(
				XpusConfigurationSection.Instance.Language.BaseDirectory);

			string[] subFolders = Directory.GetDirectories(path);
			_strings = new Dictionary<string, Dictionary<string, string>>();
			foreach(string folder in subFolders)
			{
				DirectoryInfo di = new DirectoryInfo(folder);
				FileInfo[] fis = di.GetFiles();

				foreach(FileInfo fi in fis)
				{
					if(fi.Name == "strings.xml")
						LoadStringFile(di.Name.ToLower(), fi.FullName);

					// 如果添加了其他基于语言的文件，
					// 在这里添加对文件名的判断，
					// 并实现一个LoadXxxxFile方法来进行加载。
				}
			}
		}

		/// <summary>
		/// 加载某种语言的字符串文件。
		/// </summary>
		/// <param name="language">
		/// 语言的名字，也是字符串文件所在文件夹的名字。
		/// </param>
		/// <param name="filePath">字符串文件的路径。</param>
		private static void LoadStringFile(string language, string filePath)
		{
			XmlDocument xdoc = new XmlDocument();
			xdoc.Load(filePath);
			_strings[language] = new Dictionary<string, string>();
			XmlNodeList nodes = xdoc.SelectNodes("/strings/string");
			foreach(XmlNode node in nodes)
			{
				XmlNode nameNode = node.SelectSingleNode("@name");
				string name = nameNode.Value;
				string value = node.InnerText;

				_strings[language].Add(name, value);
			}
		}
	}
}
